﻿using Microsoft.Build.Evaluation;
using OD.ProjectCustomizationTool.Helpers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OD.ProjectCustomizationTool
{
    internal abstract class ProjectToolBase
    {
        #region Properties

        private Boolean IsInitialized; // = false;

        /// <summary>
        /// Accessor to the projet monitor.
        /// </summary>
        protected IProjectMonitor Monitor { get; private set; }

        /// <summary>
        /// The full path to the solution folder.
        /// </summary>
        protected DirectoryInfo SolutionRoot { get; private set; }

        /// <summary>
        /// Accessor to the current project.
        /// </summary>
        protected Project CurrentProject { get { return this.Monitor.CurrentProject; } }

        /// <summary>
        /// The full path to the project file.
        /// </summary>
        public String FullPathToProj { get { return this.CurrentProject.FullPath; } }

        private static readonly IDictionary<Guid, EProjectType> ProjectTypesGuidToEnum = ProjectToolBase.IntializeProjectTypesGuidToEnum();

        /// <summary>
        /// Retrieve the type list of the current project.
        /// </summary>
        protected IEnumerable<EProjectType> ProjectTypes
        {
            get
            {
                if (this.FullPathToProj.EndsWith(".modelproj"))
                {
                    yield return EProjectType.Modeling;
                }
                else
                {
                    var guids = this.CurrentProject
                        .GetPropertyValue(Properties.Resources.ProjectTypeGuidsProjectProperty)
                        .Split(';')
                        .Where(x => !String.IsNullOrEmpty(x))
                        .Select(x => Guid.Parse(x));

                    foreach (var item in guids)
                    {
                        if (ProjectToolBase.ProjectTypesGuidToEnum.ContainsKey(item))
                        {
                            yield return ProjectToolBase.ProjectTypesGuidToEnum[item];
                        }
                        else
                        {
                            yield return EProjectType.Unknown;
                        }
                    }
                }
            }
        }

        #endregion

        #region Methods

        private static IDictionary<Guid, EProjectType> IntializeProjectTypesGuidToEnum()
        {
            var result = new Dictionary<Guid, EProjectType>();
            result.Add(Guid.Parse("{3AC096D0-A1C2-E12C-1390-A8335801FDAB}"), EProjectType.Test);
            return result;
        }

        /// <summary>
        /// Initialize the project updater tool for a specific project.
        /// </summary>
        /// <param name="monitor">The monitor that surveys the tool.</param>
        public void Initialize(IProjectMonitor monitor)
        {
            if (monitor == null)
            {   // This code has been generated from the 'argnull' custom snippet.
                throw new ArgumentNullException("monitor");
            }

            if (this.IsInitialized)
            {
                throw new InvalidOperationException("This project tool has already been initialized.");
            }
            else
            {
                this.IsInitialized = true;
            }

            this.Monitor = monitor;
            this.SolutionRoot = this.FindSolutionRoot(Directory.GetParent(this.FullPathToProj));
            this.InternalInitialize();
        }

        /// <summary>
        /// Allow post initialization here.
        /// </summary>
        protected virtual void InternalInitialize()
        {   // Nothing to do here.
        }

        private DirectoryInfo FindSolutionRoot(DirectoryInfo path)
        {
            if (path == null)
                return null;
            if (Directory.GetFiles(path.FullName, Properties.Resources.SolutionFileSearchPattern).Count() > 0)
                return path;
            return this.FindSolutionRoot(path.Parent);
        }

        /// <summary>
        /// Update the project file considering the context of this tool.
        /// The associated quality file may be created, the project is opened and ready for edit,
        /// the custom update is applyed and the project is saved.
        /// <remarks>The file may be a link to .Quality common folder.</remarks>
        /// </summary>
        public void Update()
        {
            if (!this.IsInitialized)
            {
                throw new InvalidOperationException("This project tool has not been initialized.");
            }

            this.BeforeUpdate();
            this.InternalUpdate();
        }

        protected virtual void BeforeUpdate()
        {   // Per default, there is noting to do in particular.
        }

        /// <summary>
        /// Updates the project considering the context of this tool.
        /// <param name="project">The opened project that is ready for edit.</param>
        /// </summary>
        protected abstract void InternalUpdate();

        #endregion
    }
}
